/*
 * *
 *  * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 *
 *
 */

package com.iwindplus.mgt.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.iwindplus.boot.domain.exception.BizException;
import com.iwindplus.mgt.domain.constant.MgtConstant;
import com.iwindplus.mgt.domain.dto.InitDataDTO;
import com.iwindplus.mgt.domain.dto.power.PositionDTO;
import com.iwindplus.mgt.domain.dto.power.PositionRoleDTO;
import com.iwindplus.mgt.domain.dto.power.RoleMenuDTO;
import com.iwindplus.mgt.domain.dto.power.RoleResourceDTO;
import com.iwindplus.mgt.domain.dto.power.UserDepartmentDTO;
import com.iwindplus.mgt.domain.dto.power.UserGroupRoleDTO;
import com.iwindplus.mgt.domain.dto.power.UserGroupUserDTO;
import com.iwindplus.mgt.domain.dto.power.UserOrgDTO;
import com.iwindplus.mgt.domain.dto.power.UserPositionDTO;
import com.iwindplus.mgt.domain.enums.MgtCodeEnum;
import com.iwindplus.mgt.server.model.power.PositionDO;
import com.iwindplus.mgt.server.model.power.PositionRoleDO;
import com.iwindplus.mgt.server.model.power.RoleDO;
import com.iwindplus.mgt.server.model.power.RoleMenuDO;
import com.iwindplus.mgt.server.model.power.RoleResourceDO;
import com.iwindplus.mgt.server.model.power.UserDepartmentDO;
import com.iwindplus.mgt.server.model.power.UserGroupRoleDO;
import com.iwindplus.mgt.server.model.power.UserGroupUserDO;
import com.iwindplus.mgt.server.model.power.UserOrgDO;
import com.iwindplus.mgt.server.model.power.UserPositionDO;
import com.iwindplus.mgt.server.service.InitService;
import com.iwindplus.mgt.server.service.power.DepartmentService;
import com.iwindplus.mgt.server.service.power.OrgService;
import com.iwindplus.mgt.server.service.power.PositionRoleService;
import com.iwindplus.mgt.server.service.power.PositionService;
import com.iwindplus.mgt.server.service.power.RoleMenuService;
import com.iwindplus.mgt.server.service.power.RoleResourceService;
import com.iwindplus.mgt.server.service.power.RoleService;
import com.iwindplus.mgt.server.service.power.SystemService;
import com.iwindplus.mgt.server.service.power.UserDepartmentService;
import com.iwindplus.mgt.server.service.power.UserGroupRoleService;
import com.iwindplus.mgt.server.service.power.UserGroupService;
import com.iwindplus.mgt.server.service.power.UserGroupUserService;
import com.iwindplus.mgt.server.service.power.UserOrgService;
import com.iwindplus.mgt.server.service.power.UserPositionService;
import com.iwindplus.mgt.server.service.power.UserService;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 初始化业务层接口实现类.
 *
 * @author zengdegui
 * @since 2024/08/16 22:42
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class InitServiceImpl implements InitService {

    @Resource
    private SystemService systemService;

    @Resource
    private RoleService roleService;

    @Resource
    private RoleMenuService roleMenuService;

    @Resource
    private RoleResourceService roleResourceService;

    @Resource
    private PositionRoleService positionRoleService;

    @Resource
    private UserGroupRoleService userGroupRoleService;

    @Resource
    private UserGroupService userGroupService;

    @Resource
    private DepartmentService departmentService;

    @Resource
    private PositionService positionService;

    @Resource
    private UserOrgService userOrgService;

    @Resource
    private UserDepartmentService userDepartmentService;

    @Resource
    private UserPositionService userPositionService;

    @Resource
    private UserGroupUserService userGroupUserService;

    @Resource
    private OrgService orgService;

    @Resource
    private UserService userService;

    @Override
    public Boolean initData(InitDataDTO entity) {
        Long userId = entity.getUserId();
        Set<Long> roleIds = entity.getRoleIds();
        Long orgId = entity.getOrgId();
        this.checkParam(entity);
        // 初始化角色菜单资源至新组织.
        Map<Long, Long> roleIdMap = this.initRoleMenuResourceToOrg(orgId, roleIds);
        // 初始化用户组至新组织.
        Map<Long, Long> userGroupIdMap = this.initUserGroupToOrg(orgId, roleIdMap);
        if (MapUtil.isNotEmpty(userGroupIdMap)) {
            // 初始化用户组用户关系
            this.initUserToUserGroup(userId, userGroupIdMap);
        }
        List<PositionRoleDO> positionRoleList = this.positionRoleService.list(Wrappers.lambdaQuery(PositionRoleDO.class)
            .in(PositionRoleDO::getRoleId, roleIdMap.keySet()));
        if (CollUtil.isNotEmpty(positionRoleList)) {
            // 初始化职位角色关系
            this.initPositionToRole(roleIdMap, positionRoleList);
            // 初始化组织（部门，职位，职位角色关系）
            this.initOrgDataToOrg(roleIdMap, positionRoleList, orgId, userId);
            return Boolean.TRUE;
        }
        return Boolean.TRUE;
    }

    private void checkParam(InitDataDTO entity) {
        Long orgId = entity.getOrgId();
        Long userId = entity.getUserId();
        Set<Long> roleIds = entity.getRoleIds();
        if (CollUtil.isEmpty(this.roleService.list(Wrappers.lambdaQuery(RoleDO.class).in(RoleDO::getId, roleIds)))) {
            throw new BizException(MgtCodeEnum.ROLE_NOT_EXIST);
        }
        if (Objects.nonNull(userId) && Objects.isNull(this.userService.getById(userId))) {
            throw new BizException(MgtCodeEnum.USER_NOT_EXIST);
        }

        if (Objects.nonNull(orgId) && Objects.isNull(this.orgService.getById(orgId))) {
            throw new BizException(MgtCodeEnum.ORG_NOT_EXIST);
        }
    }

    private Map<Long, Long> initRoleMenuResourceToOrg(Long orgId, Set<Long> roleIds) {
        if (Objects.isNull(orgId)) {
            return Collections.emptyMap();
        }
        Set<Long> roleIdSet = Set.copyOf(roleIds);
        List<RoleMenuDO> roleMenuList = this.roleMenuService.list(Wrappers.lambdaQuery(RoleMenuDO.class)
            .in(RoleMenuDO::getRoleId, roleIds));
        if (CollUtil.isEmpty(roleMenuList)) {
            return Collections.emptyMap();
        }
        // 初始化角色
        Map<Long, Long> roleIdMap = this.roleService.editInitToClient(orgId, roleIdSet);
        // 初始化角色菜单关系
        roleMenuList.forEach(roleMenu -> {
            roleMenu.setId(null);
            roleMenu.setVersion(0);
            roleMenu.setRoleId(roleIdMap.get(roleMenu.getRoleId()));
            roleMenu.setRemark(MgtConstant.REMARK_INIT);
        });
        List<RoleMenuDTO> roleMenuDtoList = BeanUtil.copyToList(roleMenuList, RoleMenuDTO.class);
        this.roleMenuService.saveBatch(roleMenuDtoList);

        List<RoleResourceDO> roleResourceList = this.roleResourceService.list(Wrappers.lambdaQuery(RoleResourceDO.class)
            .in(RoleResourceDO::getRoleId, roleIds));
        if (CollUtil.isEmpty(roleResourceList)) {
            return Collections.emptyMap();
        }
        // 初始化角色资源关系
        roleResourceList.forEach(roleResource -> {
            roleResource.setId(null);
            roleResource.setVersion(0);
            roleResource.setRoleId(roleIdMap.get(roleResource.getRoleId()));
            roleResource.setRemark(MgtConstant.REMARK_INIT);
        });
        List<RoleResourceDTO> roleResourceDtoList = BeanUtil.copyToList(roleMenuList, RoleResourceDTO.class);
        this.roleResourceService.saveBatch(roleResourceDtoList);
        return roleIdMap;
    }

    private Map<Long, Long> initUserGroupToOrg(Long orgId, Map<Long, Long> roleIdMap) {
        if (Objects.isNull(orgId)) {
            return Collections.emptyMap();
        }
        Set<Long> roleIds = roleIdMap.keySet();
        List<UserGroupRoleDO> userGroupRoleList = this.userGroupRoleService.list(Wrappers.lambdaQuery(UserGroupRoleDO.class)
            .in(UserGroupRoleDO::getRoleId, roleIds));
        if (CollUtil.isEmpty(userGroupRoleList)) {
            return Collections.emptyMap();
        }
        Set<Long> userGroupIdSet = userGroupRoleList.stream().map(UserGroupRoleDO::getUserGroupId).collect(Collectors.toSet());
        // 初始化用户组
        Map<Long, Long> userGroupIdMap = this.userGroupService.editInitToOrg(orgId, userGroupIdSet);
        // 初始化用户组角色关系
        userGroupRoleList.forEach(userGroupRole -> {
            userGroupRole.setId(null);
            userGroupRole.setVersion(0);
            userGroupRole.setRoleId(roleIdMap.get(userGroupRole.getRoleId()));
            userGroupRole.setRemark(MgtConstant.REMARK_INIT);
        });
        List<UserGroupRoleDTO> userGroupRoleDtoList = BeanUtil.copyToList(userGroupRoleList, UserGroupRoleDTO.class);
        this.userGroupRoleService.saveBatch(userGroupRoleDtoList);
        return userGroupIdMap;
    }

    private void initOrgDataToOrg(Map<Long, Long> roleIdMap, List<PositionRoleDO> positionRoleList, Long orgId, Long userId) {
        Set<Long> positionIdList = positionRoleList.stream().map(PositionRoleDO::getPositionId).collect(Collectors.toSet());
        List<PositionDO> positionList = this.positionService.list(Wrappers.lambdaQuery(PositionDO.class).in(PositionDO::getId, positionIdList));
        if (CollUtil.isEmpty(positionList)) {
            return;
        }
        Set<Long> departmentIdList = positionList.stream().map(PositionDO::getDepartmentId).collect(Collectors.toSet());
        // 初始化部门
        Map<Long, Long> departmentIdMap = this.departmentService.editInitToOrg(orgId, departmentIdList);
        // 初始化职位
        List<PositionDTO> positionDtoList = BeanUtil.copyToList(positionList, PositionDTO.class);
        Map<Long, Long> positionIdMap = this.positionService.editInitToDepartment(orgId, departmentIdMap, positionDtoList);
        positionRoleList.forEach(positionRole -> {
            positionRole.setId(null);
            positionRole.setVersion(0);
            positionRole.setPositionId(positionIdMap.get(positionRole.getPositionId()));
            positionRole.setRoleId(roleIdMap.get(positionRole.getRoleId()));
            positionRole.setRemark(MgtConstant.REMARK_INIT);
        });
        // 初始化职位角色关系
        List<PositionRoleDTO> positionRoleDtoList = BeanUtil.copyToList(positionRoleList, PositionRoleDTO.class);
        this.positionRoleService.saveBatch(positionRoleDtoList);

        // 初始化用户组织关系
        this.initUserToOrg(roleIdMap, orgId, userId);

        // 初始化用户部门关系
        this.initUserToDepartment(userId, departmentIdMap);

        // 初始化用户职位关系
        this.initUserToPosition(userId, positionIdMap);
    }

    private void initPositionToRole(Map<Long, Long> roleIdMap, List<PositionRoleDO> positionRoleList) {
        if (CollUtil.isEmpty(positionRoleList)) {
            return;
        }
        positionRoleList.forEach(positionRole -> {
            positionRole.setId(null);
            positionRole.setVersion(0);
            positionRole.setRoleId(roleIdMap.get(positionRole.getRoleId()));
            positionRole.setRemark(MgtConstant.REMARK_INIT);
        });
        List<PositionRoleDTO> positionRoleDtoList = BeanUtil.copyToList(positionRoleList, PositionRoleDTO.class);
        this.positionRoleService.saveBatch(positionRoleDtoList);
    }

    private void initUserToOrg(Map<Long, Long> roleIdMap, Long orgId, Long userId) {
        if (Objects.isNull(userId)) {
            return;
        }
        List<Long> roleIds = new ArrayList<>(roleIdMap.keySet());
        Long roleId = roleIds.get(0);
        final RoleDO role = this.roleService.getById(roleId);
        if (Objects.isNull(role)) {
            return;
        }
        List<UserOrgDO> userOrgList = this.userOrgService.list(Wrappers.lambdaQuery(UserOrgDO.class)
            .eq(UserOrgDO::getUserId, userId)
            .eq(UserOrgDO::getChecked, Boolean.TRUE));
        if (CollUtil.isEmpty(userOrgList)) {
            return;
        }
        userOrgList.forEach(userOrg -> {
            userOrg.setId(null);
            userOrg.setVersion(0);
            userOrg.setOrgId(orgId);
            userOrg.setRemark(MgtConstant.REMARK_INIT);
        });
        List<UserOrgDTO> userOrgDtoList = BeanUtil.copyToList(userOrgList, UserOrgDTO.class);
        this.userOrgService.saveBatch(userOrgDtoList);
    }

    private void initUserToDepartment(Long userId, Map<Long, Long> departmentIdMap) {
        if (Objects.isNull(userId)) {
            return;
        }
        final Set<Long> departmentIds = departmentIdMap.keySet();
        List<UserDepartmentDO> userDepartmentList = this.userDepartmentService.list(Wrappers.lambdaQuery(UserDepartmentDO.class)
            .in(UserDepartmentDO::getDepartmentId, departmentIds)
            .eq(UserDepartmentDO::getUserId, userId));
        if (CollUtil.isEmpty(userDepartmentList)) {
            return;
        }
        userDepartmentList.forEach(userDepartment -> {
            userDepartment.setId(null);
            userDepartment.setVersion(0);
            userDepartment.setDepartmentId(departmentIdMap.get(userDepartment.getDepartmentId()));
            userDepartment.setRemark(MgtConstant.REMARK_INIT);
        });
        // 初始化用户部门关系
        List<UserDepartmentDTO> userDepartmentDtoList = BeanUtil.copyToList(userDepartmentList, UserDepartmentDTO.class);
        this.userDepartmentService.saveBatch(userDepartmentDtoList);
    }

    private void initUserToPosition(Long userId, Map<Long, Long> positionIdMap) {
        if (Objects.isNull(userId)) {
            return;
        }
        final Set<Long> positionIds = positionIdMap.keySet();
        List<UserPositionDO> userPositionList = this.userPositionService.list(Wrappers.lambdaQuery(UserPositionDO.class)
            .in(UserPositionDO::getPositionId, positionIds)
            .eq(UserPositionDO::getUserId, userId));
        if (CollUtil.isEmpty(userPositionList)) {
            return;
        }
        userPositionList.forEach(userPosition -> {
            userPosition.setId(null);
            userPosition.setVersion(0);
            userPosition.setPositionId(positionIdMap.get(userPosition.getPositionId()));
            userPosition.setRemark(MgtConstant.REMARK_INIT);
        });
        // 初始化用户职位关系
        List<UserPositionDTO> userPositionDtoList = BeanUtil.copyToList(userPositionList, UserPositionDTO.class);
        this.userPositionService.saveBatch(userPositionDtoList);
    }

    private void initUserToUserGroup(Long userId, Map<Long, Long> userGroupIdMap) {
        if (Objects.isNull(userId)) {
            return;
        }
        final Set<Long> groupIds = userGroupIdMap.keySet();
        List<UserGroupUserDO> userGroupUserList = this.userGroupUserService.list(Wrappers.lambdaQuery(UserGroupUserDO.class)
            .in(UserGroupUserDO::getUserGroupId, groupIds)
            .eq(UserGroupUserDO::getUserId, userId));
        if (CollUtil.isEmpty(userGroupUserList)) {
            return;
        }
        userGroupUserList.forEach(userGroupUser -> {
            userGroupUser.setId(null);
            userGroupUser.setVersion(0);
            userGroupUser.setUserGroupId(userGroupIdMap.get(userGroupUser.getUserGroupId()));
            userGroupUser.setRemark(MgtConstant.REMARK_INIT);
        });
        // 初始化用户组用户关系
        List<UserGroupUserDTO> userGroupUserDtoList = BeanUtil.copyToList(userGroupUserList, UserGroupUserDTO.class);
        this.userGroupUserService.saveBatch(userGroupUserDtoList);
    }
}
